//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <protocol.h>
#include <reply.h>
#include "gprocess.h"
#include "gthread.h"
#include "genumerator.h"
#include "gmutex.h"
#include "gevent.h"
#include "gcondition.h"
#include "gsharedmem.h"
#include "gtag.h"
#include <aura.h>

EXTERN ECode STDCALL CreateServiceCentral();
EXTERN void  STDCALL DestroyServiceCentral();

DECL_HANDLER(create_gprocess)
{
    WString name = (wchar_t *)get_req_data(req, 0);
    WString args = (wchar_t *)get_req_data(req, 1);

    return CGhostProcess::S_Create(name, args, req->processId);
}

DECL_HANDLER(start_process)
{
    CGhostProcess * pGhost = NULL;
    CGhostTag  * pTag  = NULL;
    ECode ec = NOERROR;

    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, &pTag);
    if (FAILED(ec)) {
        return ec;
    }

    WString name = (wchar_t*)get_req_data(req, 0);
    WString args = (wchar_t*)get_req_data(req, 1);

    CGhostProcessFactory factory(req->priorityRank, req->capacity, name, args);
    ec = Ghost::S_CreateGhost(&factory, (Ghost**)&pGhost, NULL);
    if (FAILED(ec)) {
        CGhostTag::S_Delete(pTag);
        return ec;
    }

    CGhostTag::S_Attach(pTag, pGhost);
    pGhost->GetId(&reply->processId);

    return NOERROR;
}

DECL_HANDLER(kill_process)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    CGhostTag::S_Delete(req->processId); // delete all refered (or hosted) ghosts.

    ec = pGhost->Kill(req->exitCode);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(waitfor_process_toexit)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->WaitForExit(req->timeOut, &reply->waitResult);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(process_IsAlive)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->IsAlive(&reply->bIsAlive);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(get_process_startInfo)
{
    CGhostProcess  * pGhost = NULL;
    WStringBuf * pName = NULL;
    WStringBuf * pArgs = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    pGhost->GetStartInfo(&pName, &pArgs);

    Int32 nameLength = pName->GetLength() + 1;
    Int32 argsLength = pArgs->GetLength() + 1;

    set_reply_data(req, 0, pName->GetPayload(), nameLength * sizeof(wchar_t));
    set_reply_data(req, 1, pArgs->GetPayload(), argsLength * sizeof(wchar_t));

    pGhost->Release();

    return ec;
}

DECL_HANDLER(get_process_exitCode)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    ec = pGhost->GetExitCode(&reply->exitCode);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(get_process_startTime)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->GetStartTime(&reply->time);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(get_process_exitTime)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->GetExitTime(&reply->time);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(get_process_processorTimes)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    ec = pGhost->GetProcessorTimes(&reply->userTime,
                                &reply->privilegedTime);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(release_process)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = CGhostTag::S_Delete(req->requestPid, pGhost);
    assert(SUCCEEDED(ec));
    pGhost->Release(); // for request to release.

    pGhost->Release(); // for "S_GetGhost" method;

    return ec;
}

DECL_HANDLER(addref_thread)
{
    Boolean bExisted = FALSE;
    Ghost * pGhost  = NULL;
    ECode ec = NOERROR;

    CGhostThreadFactory factory(req->threadId);
    ec = Ghost::S_CreateGhost(&factory, &pGhost, &bExisted);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, pGhost);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    if (!bExisted) {
        ec = CGhostTag::S_Create(req->hostPid, LabelType_Host, pGhost);
        if (FAILED(ec)) {
            goto ErrorExit;
        }
    }
    return ec;

ErrorExit:
    if (NULL != pGhost) {
        CGhostTag::S_Delete(req->requestPid, pGhost);
        pGhost->Release();
    }

    return ec;
}

DECL_HANDLER(release_thread)
{
    CGhostThread * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostThreadFactory factory(req->threadId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    CGhostTag::S_Delete(req->requestPid, pGhost);
    pGhost->Release(); // for request to release;
    pGhost->Release(); // for "S_Find" method;

    return ec;
}

DECL_HANDLER(get_thread_quitCode)
{
    CGhostThread * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostThreadFactory factory(req->threadId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    pGhost->GetQuitCode(&reply->quitCode);
    pGhost->Release();

    return NOERROR;
}

DECL_HANDLER(get_thread_startTime)
{
    CGhostThread * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostThreadFactory factory(req->threadId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    pGhost->GetStartTime(&reply->time);
    pGhost->Release();

    return NOERROR;
}

DECL_HANDLER(get_thread_quitTime)
{
    CGhostThread * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostThreadFactory factory(req->threadId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    pGhost->GetQuitTime(&reply->time);
    pGhost->Release();

    return NOERROR;
}

DECL_HANDLER(get_thread_name)
{

    CGhostThread * pGhost = NULL;
    WStringBuf   * pName  = NULL;
    ECode ec = NOERROR;

    CGhostThreadFactory factory(req->threadId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    pGhost->GetName(&pName);
    Int32 length = pName->GetLength() + 1;
    set_reply_data(req, 0, pName->GetPayload(), length * sizeof(wchar_t));
    pGhost->Release();

    return NOERROR;
}

DECL_HANDLER(transfer_thread_info)
{
    CGhostThread * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostThreadFactory factory(req->threadId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) { // skipped with "OK" if not exist.
        return NOERROR;
    }

    CGhostTag::S_Delete(req->processId, pGhost);
    WString name = (wchar_t *)get_req_data(req, 0);
    pGhost->DoAtQuit(req->quitCode,
                  req->startTime,
                  req->quitTime,
                  name);
    pGhost->Release(); // release for "S_GetGhost";

    return NOERROR;
}

DECL_HANDLER(transfer_process_info)
{
    CGhostProcess * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(req->processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    CGhostTag::S_Delete(req->processId); // delete all refered (or hosted) ghosts.
    pGhost->DoAtExit(req->exitCode,
                     req->userTime,
                     req->privilegedTime);
    pGhost->Release(); // for Process itself to exit.
    pGhost->Release(); // for "S_GetGhost" method;
    return ec;
}

DECL_HANDLER(create_enumerator)
{
    CGhostEnumerator * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostEnumeratorFactory factory(&CGhostProcess::s_activeList,
                                    &CGhostProcess::s_activeListState,
                                    CGhostProcess::s_hLock);
    ec = Ghost::S_CreateGhost(&factory, (Ghost**)&pGhost, NULL);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, pGhost);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    pGhost->GetId(&reply->enumeratorId);

    return NOERROR;

ErrorExit:
    if (NULL != pGhost) {
        pGhost->Release();
        pGhost = NULL;
    }
    return ec;
}

DECL_HANDLER(get_current)
{
    CGhostEnumerator * pGEnumeratr = NULL;
    CGhostProcess    * pGProcess   = NULL;
    ECode ec = NOERROR;

    CGhostEnumeratorFactory factory(req->enumeratorId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGEnumeratr);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = pGEnumeratr->Current(&pGProcess);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, pGProcess);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    pGProcess->GetId(&reply->processId);
    pGEnumeratr->Release();

    return NOERROR;

ErrorExit:
    if (NULL != pGEnumeratr) {
        pGEnumeratr->Release();
        pGEnumeratr = NULL;
    }
    if (NULL != pGProcess) {
        pGProcess->Release();
        pGProcess = NULL;
    }
    return ec;
}

DECL_HANDLER(move_next)
{
    CGhostEnumerator * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostEnumeratorFactory factory(req->enumeratorId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    ec = pGhost->MoveNext(&reply->bSucceeded);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(reset_enumerator)
{
    CGhostEnumerator * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostEnumeratorFactory factory(req->enumeratorId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    pGhost->Reset();
    pGhost->Release();

    return ec;
}

DECL_HANDLER(release_enumerator)
{
    CGhostEnumerator * pGhost = NULL;
    ECode ec = NOERROR;

    CGhostEnumeratorFactory factory(req->enumeratorId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    CGhostTag::S_Delete(req->requestPid, pGhost);
    pGhost->Release();
    pGhost->Release();

    return NOERROR;
}

DECL_HANDLER(create_namedMutex)
{
    WString name = (wchar_t *)get_req_data(req, 0);
    Boolean bExisted = FALSE;
    Ghost * pGhost =NULL;
    ECode   ec = NOERROR;

    assert(!name.IsNullOrEmpty());
    CGhostMutexFactory mutexFactory(name);
    GhostFactory factory(name, req->requestPid, &mutexFactory);
    ec = Ghost::S_CreateGhost(&factory, &pGhost, &bExisted);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, pGhost);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    reply->oid = pGhost->GetOid();
    reply->bAlreadyExisted = bExisted;

    return NOERROR;

ErrorExit:
    if (NULL != pGhost) {
        pGhost->Release();
        pGhost = NULL;
    }
    return ec;
}

DECL_HANDLER(create_namedEvent)
{
    WString name = (wchar_t *)get_req_data(req, 0);
    Boolean bExisted = FALSE;
    Ghost * pGhost   = NULL;
    ECode   ec = NOERROR;

    assert(!name.IsNullOrEmpty());
    CGhostEventFactory eventFactory(name, req->bManualReset, req->initialState);
    GhostFactory factory(name, req->requestPid, &eventFactory);
    ec = Ghost::S_CreateGhost(&factory, &pGhost, &bExisted);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, pGhost);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    reply->oid = pGhost->GetOid();
    reply->bAlreadyExisted = bExisted;

    return NOERROR;

ErrorExit:
    if (NULL != pGhost) {
        pGhost->Release();
        pGhost = NULL;
    }
    return ec;
}

DECL_HANDLER(trywait_namedEvent)
{
    GhostFactory factory(req->oid);
    CGhostEvent * pGhost = NULL;
    ECode ec = NOERROR;

    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->TryWait(req->msTimeOut, &reply->result, &reply->state);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(notify_namedEvent)
{
    GhostFactory factory(req->oid);
    CGhostEvent * pGhost = NULL;
    ECode ec = NOERROR;

    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->Notify(req->state);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(clear_namedEvent)
{
    GhostFactory factory(req->oid);
    CGhostEvent * pGhost = NULL;
    ECode ec = NOERROR;

    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->Clear();
    pGhost->Release();

    return ec;
}

DECL_HANDLER(condition_create)
{
    WString name = (wchar_t *)get_req_data(req, 0);
    Boolean bExisted = FALSE;
    Ghost * pGhost   = NULL;
    ECode   ec = NOERROR;

    assert(!name.IsNullOrEmpty());
    CGhostConditionFactory condFactory(name);
    GhostFactory factory(name, req->requestPid, &condFactory);
    ec = Ghost::S_CreateGhost(&factory, &pGhost, &bExisted);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, pGhost);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    reply->oid = pGhost->GetOid();
    reply->bAlreadyExisted = bExisted;

    return NOERROR;

ErrorExit:
    if (NULL != pGhost) {
        pGhost->Release();
        pGhost = NULL;
    }
    return ec;
}

DECL_HANDLER(condition_wait)
{
    GhostFactory factory(req->oid);
    CGhostCondition * pGhost = NULL;
    ECode ec = NOERROR;

    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    ec = pGhost->Wait(req->msTimeOut, &reply->result);
    pGhost->Release();

    return ec;
}

DECL_HANDLER(condition_pulse)
{
    GhostFactory factory(req->oid);
    CGhostCondition * pGhost = NULL;
    ECode ec = NOERROR;

    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->Pulse();
    pGhost->Release();

    return ec;
}

DECL_HANDLER(condition_pulseall)
{
    GhostFactory factory(req->oid);
    CGhostCondition * pGhost = NULL;
    ECode ec = NOERROR;

    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pGhost->PulseAll();
    pGhost->Release();

    return ec;
}

DECL_HANDLER(create_sharedmemory)
{
    WString name = (wchar_t *)get_req_data(req, 0);
    Boolean bExisted = FALSE;
    Ghost * pGhost = NULL;
    ECode ec = NOERROR;

    assert(!name.IsNullOrEmpty());
    CGhostSharedMemoryFactory shmFactory(name, req->memorySize, req->bCommit);
    GhostFactory factory(name, req->requestPid, &shmFactory);
    ec = Ghost::S_CreateGhost(&factory, &pGhost, &bExisted);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, pGhost);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    reply->oid = pGhost->GetOid();
    reply->bAlreadyExisted = bExisted;

    return NOERROR;

ErrorExit:
    if (NULL != pGhost) {
        pGhost->Release();
        pGhost = NULL;
    }

    return ec;
}

DECL_HANDLER(addref_namedobject)
{
    GhostFactory factory(req->oid);
    Ghost * pGhost = NULL;
    ECode ec= NOERROR;

    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostTag::S_Create(req->requestPid, LabelType_Refer, pGhost);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    return NOERROR;

ErrorExit:
    if (NULL != pGhost) {
        pGhost->Release();
        pGhost = NULL;
    }
    return ec;
}

DECL_HANDLER(release_namedobject)
{
    GhostFactory factory(req->oid);
    Ghost * pGhost = NULL;
    ECode ec = NOERROR;

    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ec;
    }
    CGhostTag::S_Delete(req->requestPid, pGhost);
    pGhost->Release();
    pGhost->Release();

    return ec;
}

// --------------------------------------------------

STATIC void DoAtExceptionalExit(
        /* [in] */ ProcessId processId)
{
    CGhostProcess * pGhost = NULL;
    Boolean bAlive = FALSE;
    ECode ec = NOERROR;

    CGhostProcessFactory factory(processId);
    ec = Ghost::S_GetGhost(&factory, (Ghost**)&pGhost);
    if (FAILED(ec)) {
        return ;
    }

    CGhostTag::S_Delete(processId);
    pGhost->DoAtExceptionalExit(&bAlive);
    if (bAlive) {
        pGhost->Release();
    }
    return ;
}

EXTERN_C ECode CDECL CentralInitialize()
{
    ECode ec = NOERROR;

    ec = AuraCentralContext_Set((PDoAtExceptionalExitOfProcess)DoAtExceptionalExit);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = CreateServiceCentral();
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = CGhostProcess::S_Initialize();
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostThread::S_Initialize();
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CGhostEnumerator::S_Initialize();
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = Ghost::S_Initialize();
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = CGhostTag::S_Initialize();
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    return ec;

ErrorExit:
    Ghost::S_Destroy();
    CGhostEnumerator::S_Destroy();
    CGhostThread::S_Destroy();
    CGhostProcess::S_Destroy();
    DestroyServiceCentral();
    AuraCentralContext_Clear();

    return ec;
}

EXTERN_C void CDECL CentralDestroy()
{
    CGhostTag::S_Destroy();
    Ghost::S_Destroy();
    CGhostEnumerator::S_Destroy();
    CGhostThread::S_Destroy();
    CGhostProcess::S_Destroy();
    DestroyServiceCentral();
    AuraCentralContext_Clear();

    return ;
}

EXTERN_C void CDECL CentralOnRunning()
{
    central_request_loop();
    return ;
}

